package com.bidevalution.business.impl;

import com.bidevalution.business.service.BeSectionReportService;
import com.bidevalution.dao.entity.BeSectionExpertInfo;
import com.bidevalution.dao.entity.BeSectionReport;
import com.bidevalution.dao.mapper.BeSectionExpertInfoMapper;
import com.bidevalution.dao.mapper.BeSectionReportMapper;
import com.bidevalution.service.BidResultService;
import com.bstek.ureport.Utils;
import com.bstek.ureport.export.ExportConfigure;
import com.bstek.ureport.export.ExportConfigureImpl;
import com.bstek.ureport.export.ExportManager;
import com.bstek.ureport.model.Report;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
import com.qtp.common.constants.SystemConstants;
import com.qtp.core.config.PropertiesTookit;
import com.qtp.core.util.*;
import org.apache.log4j.Logger;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.qtp.core.model.Response;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * @author 查慧英
 * @date 2019-11-12 10:07
 */
@Service(value = "beSectionReportService")
public class BeSectionReportServiceImpl implements BeSectionReportService {
    private Logger logger = Logger.getLogger(getClass());
    private static final String REPORT_PATHS = "reportPaths";
    private static final String COMMA = ",";
    private static final String PATH_FORMAT="%s%s.%s";
    private static final String NAME_FORMAT="%s%s";
    private static final String PDF_SUFFIX = "pdf";
    private static final String SECTION_ID = "sectionId";
    private static final String STEP_CODE = "stepCode";
    private static final String REPORT_EXPERT = "reportExpert";
    private static final String EXPERT_ID = "expertId";
    private static final String SECTION_CODE = "sectionCode";
    private static final String EXCEL_SUFFIX = PropertiesTookit.getValue("ureport.excel.suffix");
    @Autowired(required = false)
    BeSectionReportMapper beSectionReportMapper;
    @Autowired(required = false)
    private BeSectionExpertInfoMapper beSectionExpertInfoMapper;
    @Autowired(required = false)
    BidResultService bidResultService;
    @Override
    public Response<List<BeSectionReport>> getBeSectionReportList(Map<String, Object> parameters) {

        BeSectionExpertInfo expertInfo = getExpertInfo(parameters);
        if(expertInfo != null) {
            if (!SystemConstants.STR_1.equals(OConvertUtils.getString(expertInfo.getIsManager()))) {
                parameters.put(REPORT_EXPERT, SystemConstants.NUM_1);
            }
        }
        return Response.ok(beSectionReportMapper.list(parameters));
    }
    @Override
    public Response exportPdf(Map<String, Object> parameters, String exportPath) {
        OutputStream os = null;
        try {
            BeSectionExpertInfo expertInfo = getExpertInfo(parameters);
            parameters.put(EXPERT_ID, expertInfo.getSeqId());
            Response<List<BeSectionReport>> response = getBeSectionReportList(parameters);
            if (response.isSuccess()) {
                List<BeSectionReport> list = response.getResult();
                if (list != null && !list.isEmpty()) {
                    String reportName;
                    String pdfPath;
                    String paths;
                    Document document = null;
                    for (BeSectionReport item : list) {
                        reportName = item.getReportName();
                        parameters.put(STEP_CODE, item.getSectionStepCode());
                        paths = item.getReportPath();
                        parameters.put(REPORT_PATHS, paths);
                        pdfPath = String.format(PATH_FORMAT, exportPath, reportName, PDF_SUFFIX);
                        os = new FileOutputStream(new File(pdfPath));
                        String[] pathArr = paths.split(COMMA);
                        if (pathArr.length > SystemConstants.NUM_1) {
                            List<String> fileList = getFileList(parameters, pathArr, exportPath, reportName);
                            morePdfToPdf(fileList, os);
                        } else {
                            document = producePdf(document, os, parameters, paths);
                            document.close();
                        }
                    }
                }
            }
            return Response.ok();
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
            return Response.fail(e.getMessage());
        }finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }

    @Override
    public Response exportExcel(Map<String, Object> parameters, String exportPath) {
        SXSSFWorkbook wb = null;
        try {
            BeSectionExpertInfo expertInfo = getExpertInfo(parameters);
            parameters.put(EXPERT_ID, expertInfo.getSeqId());
            UreportExcel excel = new UreportExcel();
            Response<List<BeSectionReport>> response = getBeSectionReportList(parameters);
            if (response.isSuccess()) {
                List<BeSectionReport> list = response.getResult();
                if (list != null && !list.isEmpty()) {
                    Report report;
                    OutputStream os;
                    String reportName;
                    String reportPath;
                    String[] pathArr;
                    String excelPath;
                    for (BeSectionReport item : list) {
                        reportName = item.getReportName();
                        reportPath = item.getReportPath();
                        parameters.put(REPORT_PATHS, reportPath);
                        parameters.put(STEP_CODE, item.getSectionStepCode());
                        excelPath = String.format(PATH_FORMAT, exportPath, reportName, EXCEL_SUFFIX);
                        if (OConvertUtils.isNotEmpty(reportPath)) {
                            wb = new SXSSFWorkbook(100000);
                            os = new FileOutputStream(new File(excelPath));
                            pathArr = reportPath.split(COMMA);
                            for (int i = 0; i < pathArr.length; i++) {
                                report = Ureport2Util.getReport(pathArr[i], parameters);
                                excel.build(wb, report, null);
                            }
                            wb.write(os);
                        }
                    }
                }
            }
            return Response.ok();
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
            return Response.fail(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return Response.fail(e.getMessage());
        }finally{
            if(wb != null) {
                wb.dispose();
            }
        }
    }
    @Override
    public Response exportExcelSheet(Map<String, Object> parameters, String exportPath) {
        SXSSFWorkbook wb = new SXSSFWorkbook(100000);
        String sectionId = OConvertUtils.getString(parameters.get(SECTION_ID));
        OutputStream os = null;
        try {
            BeSectionExpertInfo expertInfo = getExpertInfo(parameters);
            parameters.put(EXPERT_ID, expertInfo.getSeqId());
            UreportExcel excel = new UreportExcel();
            Response<List<BeSectionReport>> response = getBeSectionReportList(parameters);
            if (response.isSuccess()) {
                List<BeSectionReport> list = response.getResult();
                if (list != null && !list.isEmpty()) {
                    Report report;
                    String excelPath = String.format(PATH_FORMAT, exportPath, sectionId, EXCEL_SUFFIX);
                    os = new FileOutputStream(new File(excelPath));
                    String reportName;
                    String name;
                    String reportPath;
                    String[] pathArr;
                    for (BeSectionReport item : list) {
                        reportName = item.getReportName();
                        reportPath = item.getReportPath();
                        parameters.put(REPORT_PATHS, reportPath);
                        parameters.put(STEP_CODE, item.getSectionStepCode());
                        if (OConvertUtils.isNotEmpty(reportPath)) {
                            pathArr = reportPath.split(COMMA);
                            for (int i = 0; i < pathArr.length; i++) {
                                name = reportName;
                                if (i > 0) {
                                    name = String.format(NAME_FORMAT,reportName,i);
                                }
                                report = Ureport2Util.getReport(pathArr[i], parameters);
                                excel.build(wb, report, name);
                            }
                        }
                    }
                    wb.write(os);
                }
            }
            return Response.ok();
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
            return Response.fail(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return Response.fail(e.getMessage());
        }finally{
            if(os != null) {
                try {
                    os.close();
                }catch (Exception ex) {
                    logger.error(ex.getMessage(), ex);
                }
            }
            wb.dispose();
        }
    }

    @Override
    public Response batchPrintPdf(Map<String, Object> parameters, OutputStream os) {
        Document document = null;
        try {
            BeSectionExpertInfo expertInfo = getExpertInfo(parameters);
            parameters.put(EXPERT_ID, expertInfo.getSeqId());
            Response<List<BeSectionReport>> response = getBeSectionReportList(parameters);
            if (response.isSuccess()) {
                String paths;
                List<BeSectionReport> list = response.getResult();
                if (list != null && !list.isEmpty()) {
                    for (BeSectionReport item : list) {
                        parameters.put(STEP_CODE, item.getSectionStepCode());
                        paths = item.getReportPath();
                        parameters.put(REPORT_PATHS, paths);
                        document = producePdf(document, os, parameters, paths);
                    }
                }
            }
            return Response.ok();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return Response.fail(e.getMessage());
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }

    @Override
    public Response pushPdf(Map<String, Object> parameters, String exportPath) {
        String paths = OConvertUtils.getString(parameters.get(REPORT_PATHS));
        String sectionCode = OConvertUtils.getString(parameters.get(SECTION_CODE));
        try {
            String[] pathArr = paths.split(COMMA);
            List<String> fileList = getFileList(parameters, pathArr, exportPath, sectionCode);
            exportPath = String.format(PATH_FORMAT, exportPath, sectionCode, PDF_SUFFIX);
            OutputStream os = new FileOutputStream(exportPath);
            morePdfToPdf(fileList, os);
            byte[] fileByte = fileToByte(exportPath);
            os.close();
            return bidResultService.pushPdf(sectionCode, fileByte);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);

            return Response.fail(e.getMessage());
        }
    }
    @Override
    public Response printPdf(Map<String, Object> parameters, OutputStream os) {
        try {
            BeSectionExpertInfo expertInfo = getExpertInfo(parameters);
            parameters.put(EXPERT_ID, expertInfo.getSeqId());
            String paths = OConvertUtils.getString(parameters.get(REPORT_PATHS));
            Document document = null;
            document = producePdf(document, os, parameters, paths);
            document.close();
            return Response.ok();
        } catch (Exception e) {
            logger.error(e.getMessage());
            return Response.fail(e.getMessage());
        }

    }
    /**
     * 生成pdf
     * @param document document
     * @param os os
     * @param parameters 参数
     * @param paths 报表模板路径
     * @return document
     */
    private Document producePdf(Document document, OutputStream os, Map<String, Object> parameters, String paths) {
        if (OConvertUtils.isNotEmpty(paths)) {
            String[] pathArr = paths.split(COMMA);
            Report report;
            Rectangle pageSize;
            for (int i = 0; i < pathArr.length; i++) {
                report = Ureport2Util.getReport(pathArr[i], parameters);
                pageSize = Ureport2Util.getPageSize(report);
                if (i == 0) {
                    document = Ureport2Util.getDocument(report, pageSize);
                } else {
                    document.setPageSize(pageSize);
                }
                PdfWriter writer = null;
                try {
                    writer = PdfWriter.getInstance(document, os);
                } catch (DocumentException e) {
                    logger.error(e.getMessage(), e);
                }
                Ureport2Util.produce(report, document, writer, pageSize);
            }

        }
        return document;
    }
    /**
     * 获取专家信息
     * @param parameters 参数
     * @return 专家信息
     */
    private BeSectionExpertInfo getExpertInfo(Map<String,Object> parameters) {
        String loginName = OConvertUtils.getString(parameters.get("loginName"));
        String sectionId = OConvertUtils.getString(parameters.get("sectionId"));
        return beSectionExpertInfoMapper.selectByLoginName(sectionId, loginName);
    }
    /**
     * 导出PDF并组装报表路径列表
     * @param parameters 参数
     * @param pathArr 报表模板路径
     * @param exportPath 导出路径
     * @param reportName 报表名称
     * @return 报表路径列表
     */
    private List<String> getFileList(Map<String, Object> parameters, String[] pathArr, String exportPath, String reportName) {
        ExportManager exportManager = (ExportManager) Utils.getApplicationContext().getBean(ExportManager.BEAN_ID);
        List<String> fileList = new ArrayList<>();
        ExportConfigure exportConfigure;
        OutputStream os;
        String filePath;
        try {
            for (int i = 0; i < pathArr.length; i++) {
                filePath = String.format(PATH_FORMAT, exportPath, reportName+i , PDF_SUFFIX);
                os = new FileOutputStream(new File(filePath));
                exportConfigure = new ExportConfigureImpl(pathArr[i], parameters, os);
                exportManager.exportPdf(exportConfigure);
                fileList.add(filePath);
            }
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
        return fileList;
    }
    /**
     * 合并报表
     * @param fileList 报表路径列表
     * @param os 合并的文件流
     */
    private void morePdfToPdf(List<String> fileList, OutputStream os) {
        Document document = null;
        try {
            document = new Document();
            PdfCopy copy = new PdfCopy(document, os);
            document.open();
            PdfReader reader;
            PdfImportedPage page;
            for (int i = 0; i < fileList.size(); i++) {
                reader = new PdfReader(fileList.get(i));
                // 获得总页码
                int n = reader.getNumberOfPages();
                for (int j = 1; j <= n; j++) {
                    document.newPage();
                    // 从当前Pdf,获取第j页
                    page = copy.getImportedPage(reader, j);
                    copy.addPage(page);
                    page.closePath();
                }
                reader.close();
                FileUtils.deleteFiles(fileList.get(i));
            }
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } catch (DocumentException e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }

    /**
     * 生成报表二进制流
     * @param filePath 报表路径
     * @return 报表二进制流
     */
    private byte[] fileToByte(String filePath)
    {
        FileInputStream fileInputStream = null;
        File file = new File(filePath);
        byte[] bFile = new byte[(int) file.length()];
        try {
            fileInputStream = new FileInputStream(file);
            fileInputStream.read(bFile);
            return bFile;
        }catch(Exception e){
            logger.error(e.getMessage(), e);
        }finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                }catch (Exception ex){
                    logger.error(ex.getMessage(), ex);
                }
            }
        }
        return null;
    }
}
